#include "taskQueue.h"
#include "virDir.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
typedef struct train_s{
    int length;
    int type;
    char value[1024];
}train_t;
int recvFileFromClient(int netfd,char *cwd) {
    
    train_t train;
    memset(&train,0,sizeof(train));

    int file_fb=open(cwd,O_RDWR|O_CREAT,0666);
    // ERROR_CHECK(file_fb,-1,"open");
    if(file_fb == -1)
    {
        return -1;
    }
    off_t filesize;
    recv(netfd,&train.length,sizeof(train.length),MSG_WAITALL);
    recv(netfd,&filesize,train.length,MSG_WAITALL);
    printf("filesize==%ld\n",filesize);
    bzero(&train,sizeof(train));

    struct stat statbuf;
    fstat(file_fb,&statbuf);
    off_t current_filesize=statbuf.st_size;//获得当前已传的文件大小
    send(netfd,&current_filesize,sizeof(current_filesize),MSG_NOSIGNAL);
    int lseek_ret=lseek(file_fb,current_filesize,SEEK_SET);//设置文件指向,指到文件末尾
    // ERROR_CHECK(lseek_ret,-1,"lseek");
    if(lseek_ret == -1)
    {
        return -1;
    }
    if(filesize<100*1024*1024){
        printf("小于100M\n");
        off_t total=0;
        while(1){
            printf("%5.2lf%%\r",100.0*total/filesize);
            fflush(stdout);
            recv(netfd,&train.length,sizeof(train.length),MSG_WAITALL);
            if(total==filesize || train.length == 0){
                break;
            }
            total+=train.length;
            recv(netfd,train.value,train.length,MSG_WAITALL);//如果是最后的车头为0的时，接收会阻塞吗
            write(file_fb,train.value,train.length);
            bzero(train.value,train.length);
        }
        printf("100.00%%\n");
    }else{
        printf("不小于100M\n");
        char recv_data[1024 * 1024] = {0};
        int ftruncate_add_ret = ftruncate(file_fb, filesize);

        long page_size = sysconf(_SC_PAGESIZE); // 获取系统页大小（通常 4KB）

        while (current_filesize < filesize) {
            int ret = recv(netfd, recv_data, sizeof(recv_data), 0);
            if (ret == 0) {
                printf("发送方中断\n");
                break;
            }

            // 计算对齐后的 offset（向下取整到页边界）
            off_t aligned_offset = (current_filesize / page_size) * page_size;
            // 计算映射后指针需要偏移的量（current_filesize - aligned_offset）
            size_t ptr_offset = current_filesize - aligned_offset;
           //要接收的剩余文件大小
            size_t remaining=filesize - aligned_offset;
            char *mapped = mmap(NULL, remaining, PROT_READ | PROT_WRITE, MAP_SHARED, file_fb, aligned_offset);
            if (mapped == MAP_FAILED) {
                perror("mmap");
                close(file_fb);
                return -1;
            }

            // 调整指针，使其指向接收中断位置
            char *effective_ptr = mapped + ptr_offset;
            memcpy(effective_ptr, recv_data, ret);
            // 清理映射
            munmap(mapped, remaining);
            /* current_filesize += write_length; */
            current_filesize += ret;
        }
        printf("接收完毕\n");
        ftruncate(file_fb, current_filesize);
    }
    return 0;
}
int sendFileToClient(char *fileName,int netfd,char *cwd){
    int file_fb = open(cwd, O_RDWR);
    // ERROR_CHECK(file_fb, -1, "open");
    train_t train;
    if(file_fb == -1)
    {
        train.type = -1;
        send(netfd,&train.type,sizeof(train.type), MSG_NOSIGNAL);
        return -1;
        
    }
    else{
        train.type = 0;
        send(netfd,&train.type,sizeof(train.type), MSG_NOSIGNAL);
    }
    train.length = strlen(fileName);
    memcpy(train.value, fileName, strlen(fileName));
    send(netfd, &train.length, sizeof(train.length), MSG_NOSIGNAL);
    send(netfd, train.value, train.length, MSG_NOSIGNAL); // 发文件名
    struct stat statbuf;
    fstat(file_fb, &statbuf);
    off_t filesize = statbuf.st_size;
    train.length = sizeof(filesize);
    memcpy(train.value, &filesize, sizeof(filesize));
    send(netfd, &train.length, sizeof(train.length), MSG_NOSIGNAL);
    send(netfd, train.value, train.length, MSG_NOSIGNAL); // 发文件大小
    ssize_t client_file_size = 0;
    recv(netfd, &client_file_size, sizeof(client_file_size), MSG_WAITALL); // 接收客户端文件大小

    if (filesize < 100 * 1024 * 1024)
    {
        while (1)
        { // 发文件内容
            char read_data[1024] = {0};
            int ret = read(file_fb, read_data, sizeof(read_data)); // 这里不用小火车，直接全部发送
            if (ret == 0)
            {
                printf("send small file over\n");
                break;
            }
            send(netfd, read_data, ret, MSG_NOSIGNAL);
        }
    }
    else
    {
        off_t offset = client_file_size;
        off_t CHUNK_SIZE = 1024 * 1024;         // 1MB，每次发送<=1MB的数据
        long page_size = sysconf(_SC_PAGESIZE); // 获取系统页大小（通常 4KB）

        while (offset < filesize)
        {
            size_t remaining = filesize - offset;
            size_t current_chunk_size = remaining < CHUNK_SIZE ? remaining : CHUNK_SIZE;

            // 计算对齐后的 offset（向下取整到页边界）
            off_t aligned_offset = (offset / page_size) * page_size;
            // 计算映射后指针需要偏移的量（offset - aligned_offset）,
            size_t ptr_offset = offset - aligned_offset; // ptr_offset > 0
            // 实际映射的长度 = 当前块大小 + 额外对齐偏移（避免越界）
            size_t mmap_length = current_chunk_size + ptr_offset;

            // 映射对齐后的区域
            char *mapped = mmap(NULL, mmap_length, PROT_READ, MAP_SHARED, file_fb, aligned_offset);
            if (mapped == MAP_FAILED)
            {
                perror("mmap failed");
                close(file_fb);
                return -1;
            }

            // 调整指针，使其指向文件要开始发送的位置
            char *effective_ptr = mapped + ptr_offset;
            // 实际发送的数据大小仍然是 current_chunk_size
            size_t sent = 0;
            while (sent < current_chunk_size)
            {
                ssize_t bytes_sent = send(netfd, effective_ptr + sent, current_chunk_size - sent, MSG_NOSIGNAL);
                if (bytes_sent == -1)
                {
                    perror("send failed");
                    munmap(mapped, mmap_length);
                    close(file_fb);
                    return -1;
                }
                sent += bytes_sent;
            }

            // 清理映射
            munmap(mapped, mmap_length);
            offset += current_chunk_size;
        }

        close(file_fb);
    }
    return 0;
}
